/* 
面向对象三大特性 (面试常问)
1. 封装: 函数/对象/类/模块/组件/库
2. 继承: extends
3. 多态: 多种形态
*/
(function () {
  /*
  多态
  */
  class Animal {
    name: string
    
    constructor (name: string) {
      this.name = name
    }

    run (distance: number=0) {
      console.log(`${this.name} run ${distance}m`)
    }
  }

  class Snake extends Animal {
    constructor (name: string) {
      // 调用父类型构造方法
      super(name) // 调用父类的构造方法
    }

    // 重写父类型的方法
    run (distance: number=5) {
      console.log('sliding...')
      super.run(distance) // 调用父类型的run方法
    }
  }

  class Horse extends Animal {
    constructor (name: string) {
      // 调用父类型构造方法
      super(name)
    }

    // 重写父类型的方法
    run (distance: number=50) {
      console.log('dashing...')
      // 调用父类型的一般方法
      super.run(distance)
    }
  }

   /* 父类引用指向子类对象: 父类型的引用变量可以指向任意子类型的实例对象 */
  // 定义一个让动物奔跑的函数
  // 声明需要一个父类型的对象 => 但最终传递给它的可以是当前类型的实例, 可以是任意子类型的实例
  // 那animal就有多种可能的情况(可以是animal, 也可以是snake, 也可以horse)
  // 那animal就有多种可能的形态了 => 那就是多态
  function run(animal: Animal) {
    animal.run() // 调用的一定是animal类中的run方法吗?
    // 调用的具体对象的run方法, 而不是声明类型的run方法
  }

  run(new Animal('a'))
  run(new Snake('s'))
  run(new Horse('h'))

  let animal: Animal = new Snake('s')
  animal = new Horse('h')

 
  
})()